/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package algos;
/*

 */

import static java.lang.Math.sqrt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import model.Algorithm;

/**
 *
 * @author Administrator
 */
public class SimulationModel extends Algorithm {

    private static final OptionType[] optionTypes = new OptionType[]{OptionType.EUROPEAN_CALL, OptionType.EUROPEAN_PUT, OptionType.AMERICAN_CALL, OptionType.AMERICAN_PUT, OptionType.ASIAN_PUT, OptionType.ASIAN_CALL};
    private static final String algoName = "Simulation";

    public SimulationModel() {
        super(algoName, optionTypes, new double[]{0.0,0.0});
        //super.getExtraParameters().put("Intervals", 0.0);
        //super.getExtraParameters().put("Trials", 0.0);
    }

    public SimulationModel(String companyTicker, double currentStockPrice, double strikePrice, double term, double volatility, double riskFreeRate, double[] extraParametersInput) {
        super(algoName, companyTicker, currentStockPrice, strikePrice, term, volatility, riskFreeRate, optionTypes, extraParametersInput);
        //super.getExtraParameters().put("Intervals", (double) numIntervals);
        //super.getExtraParameters().put("Trials", (double) numTrials);
    }
    
    @Override
    public void initExtraParameters(double[] extraParametersInput){
        super.getExtraParameters().put("Intervals", extraParametersInput[0]);
        super.getExtraParameters().put("Trials", extraParametersInput[1]);
    }
            
    @Override
    public double calculatePutPrice() {
        int numIntervals = ((Double) (super.getExtraParameters().get("Intervals"))).intValue();
        int numTrials = ((Double) (super.getExtraParameters().get("Trials"))).intValue();
        int i, trialCount;
        double deltaT = super.getTerm() / (double) numIntervals;
        double trialRunningSum, trialAverage, trialPayoff;
        double simulationRunningSum, simulationAveragePayoff;
        double s;
        Random rand = new Random();
        simulationRunningSum = 0.0;
        for (trialCount = 1; trialCount <= numTrials; trialCount++) {
            s = super.getCurrentStockPrice();
            trialRunningSum = 0.0;
            double nns = 0;
            for (i = 0; i < numIntervals; i++) {

                nns = rand.nextGaussian();
                s = s * Math.exp((super.getRiskFreeRate() - super.getVolatility() * super.getVolatility() / 2) * deltaT
                        + super.getVolatility() * nns * sqrt(deltaT));
                trialRunningSum += s;

            }
            trialAverage = trialRunningSum / numIntervals;
            trialPayoff = Math.max(super.getStrikePrice() - trialAverage, 0.0);
            simulationRunningSum += trialPayoff;
        }
        simulationAveragePayoff = simulationRunningSum / numTrials;
        double valueOfOption;
        valueOfOption = simulationAveragePayoff * Math.exp(-super.getRiskFreeRate() * super.getTerm());
        return valueOfOption;
    }

    public double calculateCallPrice() {
        int numIntervals = ((Double) (super.getExtraParameters().get("Intervals"))).intValue();
        int numTrials = ((Double) (super.getExtraParameters().get("Trials"))).intValue();
        int i, trialCount;
        double deltaT = super.getTerm() / (double) numIntervals;
        double trialRunningSum, trialAverage, trialPayoff;
        double simulationRunningSum, simulationAveragePayoff;
        double s;
        Random rand = new Random();
        simulationRunningSum = 0.0;
        for (trialCount = 1; trialCount <= numTrials; trialCount++) {
            s = super.getCurrentStockPrice();
            trialRunningSum = 0.0;
            double nns = 0;
            for (i = 0; i < numIntervals; i++) {

                nns = rand.nextGaussian();
                s = s * Math.exp((super.getRiskFreeRate() - super.getVolatility() * super.getVolatility() / 2) * deltaT
                        + super.getVolatility() * nns * sqrt(deltaT));
                trialRunningSum += s;

            }
            trialAverage = trialRunningSum / numIntervals;
            trialPayoff = Math.max(trialAverage - super.getStrikePrice(), 0.0);
            simulationRunningSum += trialPayoff;
        }
        simulationAveragePayoff = simulationRunningSum / numTrials;
        double valueOfOption;
        valueOfOption = simulationAveragePayoff * Math.exp(-super.getRiskFreeRate() * super.getTerm());
        return valueOfOption;

    }

    public static void main(String[] args) {
        Algorithm a = new SimulationModel("A", 50, 50, 0.4, 0.4, 0.1, new double[]{5,10});
        System.out.println(a.calculateCallPrice());
        System.out.println(a.calculatePutPrice());
        //companyTicker, currentStockPrice, strikePrice, term, volatility, riskFreeRate, numIntervals, numTrials
    }

}
